Necesitamos analizar los datos de tipo mixto, número, órdinal y nominal. Nos vamos a enfocar en clasificación no supervisada usando R CLUSTERING ALGORITHM: PARTITIONING AROUND MEDOIDS (PAM)
#setwd("C:/Users/Pablo/Desktop/Machine_Learning_I/PRAC/Cluster")
df_mas <- read.csv ("kc_house_data.csv")
#set.seeds=737
#df_mas <- sample_n(df_mas, size = 10000)
La distancia es una medida numérica de cuán separados están los individuos, es decir una métrica utilizada para medir la proximidad o similitud entre individuos;
La distancia de Gower se calcula como el promedio de las diferencias parciales entre individuos. Para cada tipo de variable, se usa una métrica de distancia particular que funciona bien para ese tipo y se escala para caer entre 0 y 1
Para las variables cuantitativa La Distancia de Manhattan Para las Variables Ordinales la Distancia un ajuste especial de la Manhattan despúes de haber sido ordenadas Para las Nominales primero se convierte en k columnas Binarias ( para cada categoria de cada variable norminal) y posteriormente se usa el coeficiente de Dice
El coeficiente de Dice [0,1] para medir la similitud entre 2 muestras
Se escala de la siguiente Manera Se define la distancia de Gower como d2ij = 1 − sij , donde sij = p1h=1 (1 − |xih − xjh|/Gh) + a + α p1 + (p2 − d) + p3 es el coeficiente de similaridad de Gower,
p1 es el numero de variables cuantitativas continuas, p2 es el numero de variables binarias, p3 es el numero de variables cualitativas(no binarias), a es el numero de coincidencias (1, 1) en las variables binarias, d es el numero de coincidencias (0, 0) en las variables binarias, α es el numero de coincidencias en las variables cualitativas (no binarias) y Gh es el rango (o recorrido) de la h-esima variable cuantitativa.
gower_dist <- daisy(df_mas, metric = "gower")
## Warning in daisy(df_mas, metric = "gower"): binary variable(s) 9 treated as
## interval scaled
gower_mat <- as.matrix(gower_dist)
df_mas[which(gower_mat == min(gower_mat[gower_mat != min(gower_mat)]),
arr.ind = TRUE)[1, ], ]
## id date price bedrooms bathrooms sqft_living sqft_lot
## 15882 125059178 7/22/2014 510000 6 4.5 3300 7480
## 7645 125059138 7/22/2014 510000 6 4.5 3300 7561
## floors waterfront view condition grade sqft_above sqft_basement
## 15882 2 0 0 3 8 3300 0
## 7645 2 0 0 3 8 3300 0
## yr_built yr_renovated zipcode lat long sqft_living15
## 15882 1980 0 98052 47.6796 -122.104 2470
## 7645 1980 0 98052 47.6795 -122.104 2470
## sqft_lot15
## 15882 7561
## 7645 7561
df_mas[which(gower_mat == max(gower_mat[gower_mat != max(gower_mat)]),
arr.ind = TRUE)[1, ], ]
## id date price bedrooms bathrooms sqft_living
## 15317 9536600010 12/23/2014 520000 4 0.75 1960
## 12765 1225069038 5/5/2014 2280000 7 8.00 13540
## sqft_lot floors waterfront view condition grade sqft_above
## 15317 8277 1 1 4 4 7 1320
## 12765 307752 3 0 4 3 12 9410
## sqft_basement yr_built yr_renovated zipcode lat long
## 15317 640 1923 1986 98198 47.3648 -122.325
## 12765 4130 1999 0 98053 47.6675 -121.986
## sqft_living15 sqft_lot15
## 15317 1940 8402
## 12765 4850 217800
Una vez calculada la matriz de distancia emplearemos el algoritmo PAM, basado en una partición de medoids (El término medoids se refiere a un objeto dentro de un grupo para el cual la diferencia promedio entre este y todos los demás miembros del grupo es mínima, es decir el punto más centralmente ubicado del conjunto de datos), en cambio en el método K-means cada Cluster está representado por su centroide. Es un método muy similar a k-means, pero es mucho más robusto a la presencia de Outliers como es en nuestro caso. Es un procedimiento de agrupación iterativa que implica los siguientes pasos:
Elejir k entidades aleatorias para convertirse en los Medoids
Asignamos a cada entidad, en nuestro caso a cada “casa” el medoide más cercano basado en la distancia de Gower anteriormente calculada.
Para cada Cluster identificar la observación que produciría la distancia promedio más baja si fuera reasiganada como el Medoid, si fuera así hay que hacer de esta observación el nuevo Medoid. Si al menos un Medoid ha cambiado volvemos Step2, en caso contrario Step4
FIN
K Means intenta mininizar el ECM total K Medoids minimiza la suma de las diferencias entre los puntos etiquetados para estar en un grupo y un punto designado como el centro de ese grupo Mediod.
Silhouette, Validación y consistencia dentro de los datos.
Es una medida de cuan similar es objeto dentro del grupo de pertenencia y cuan disimilar con los otros grupos.
Varía entre -1 y 1. Un valor alto indica que un objeto está bien emparejado dentro de su grupo y mal con el resto. Un valor muy bajo o negativo implica una revisión del número de cluster al alza o a la baja
sil_width <- c(NA)
for(i in 2:10){
pam_fit <- pam(gower_dist, diss = TRUE, k = i)
sil_width[i] <- pam_fit$silinfo$avg.width
}
plot(1:10, sil_width,
xlab = "Numero de clusters",
ylab = "Silhouette")
lines(1:10, sil_width)
#fviz_silhouette(pam_fit)
Después de calcular el Silhouette para el algoritmo PAM vemos que 2 grupos producen el valor más alto. Aún asi nosotros seleccionamos 3 Cluster para dividir la dispersión del Trabajo y facilitar el entendimiento de los siguientes análisis.
set.seed=737
k <- 3
pam_fit <- pam(gower_dist, diss = TRUE, k)
pam_results <- df_mas %>%
mutate(cluster = pam_fit$clustering) %>%
group_by(cluster) %>%
do(the_summary = summary(.))
#frecuencia del número de casas en cada Clúster
ftable(pam_fit$clustering)
## 1 2 3
##
## 7255 5687 8655
df_mas$cluster<-pam_fit$clustering
maps <- data.frame (long=df_mas$long, lat=df_mas$lat, cluster=df_mas$cluster, precio=df_mas$price,code=df_mas$zipcode)
states <- map_data("state")
dim(states)
## [1] 15537 6
washington <- subset(states, region %in% c("washington"))
ca_base <- ggplot(data = washington, mapping = aes(x = long, y = lat, group = group, fill=group)) + coord_fixed(1.3) + geom_polygon(color = "black", fill = "white")
counties <- map_data("county")
ca_county <- subset(counties, region == "washington")
ca_base +
geom_polygon(data = ca_county, fill = NA, color = "white") +
geom_polygon(color = "black", fill = NA) + scale_fill_identity() +
ggtitle("washington") +
geom_point(data = maps, aes(x = long,y = lat), color=maps$cluster, size = 0.1 ,inherit.aes = FALSE )
ca_base +
geom_polygon(data = ca_county, fill = NA, color = "white") + coord_map(xlim = c(-123,-121),ylim = c(47, 48))+
geom_polygon(color = "black", fill = NA) +
ggtitle("washington") + guides(fill=FALSE) +
geom_point(data = maps, aes(x = long,y = lat), color=maps$cluster, size = 0.5 ,inherit.aes = FALSE )
## Coordinate system already present. Adding new coordinate system, which will replace the existing one.
df_mas %>%
group_by(cluster) %>%
summarise(num_casas=n(), precio= mean(price), room=mean(bedrooms),baths=mean(bathrooms) ,
tamanyo=mean(sqft_living), anyo=mean(yr_built), grade=mean(grade), floor=mean(floors) ,visitas=mean(view))
## # A tibble: 3 x 10
## cluster num_casas precio room baths tamanyo anyo grade floor visitas
## <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 7255 498294. 3.11 1.66 1679. 1944. 7.06 1.22 0.257
## 2 2 5687 412375. 3.34 1.85 1808. 1968. 7.19 1.07 0.172
## 3 3 8655 659559. 3.61 2.67 2595. 1996. 8.46 2.00 0.256
Grupo de Precio Mediano, con menor número de Habtaciones y Baños en Media. Menor tamaño de metros cuadrados de la vivienda. Grupo de Peor Grado de Vivienda. Casas de mayor Antigüedad
Grupo de Precio Más Bajo. Grupo que menor número de visitas Recibe, casí todas de planta única. Casas de los años 60,70.
Precio Más Alto en Media , mayor número de Baños, metros, habitaciones y Plantas Casas más nuevas
El PCA es un algoritmo lienal, no podrá interpretar relaciones complejas polinómicas entre los items del dataset. Vemos que en los dos primeros componentes recogemos el 50,35% de la variabilidad Seleccionando aquellos componentes con autovalor mayor a 1,los Cuatro Primeros, explican el 71,5% de la variabilidad total.
data<- subset(df_mas, select=c("price", "bedrooms","bathrooms","sqft_living","sqft_lot","floors","waterfront", "view","condition","grade","sqft_above","sqft_basement","sqft_living15","sqft_lot15"))
pca<- prcomp(data, scale=TRUE)
summary (pca)
## Importance of components:
## PC1 PC2 PC3 PC4 PC5 PC6
## Standard deviation 2.3011 1.3243 1.2962 1.13156 0.91171 0.84205
## Proportion of Variance 0.3782 0.1253 0.1200 0.09146 0.05937 0.05065
## Cumulative Proportion 0.3782 0.5035 0.6235 0.71497 0.77435 0.82499
## PC7 PC8 PC9 PC10 PC11 PC12
## Standard deviation 0.76064 0.72717 0.59531 0.5292 0.51397 0.48516
## Proportion of Variance 0.04133 0.03777 0.02531 0.0200 0.01887 0.01681
## Cumulative Proportion 0.86632 0.90409 0.92940 0.9494 0.96827 0.98508
## PC13 PC14
## Standard deviation 0.45697 1.995e-15
## Proportion of Variance 0.01492 0.000e+00
## Cumulative Proportion 1.00000 1.000e+00
fviz_eig(pca)
A través de los Scores de cada variable dentro del componente Principal podemos libremente afirmar y con fines explicativos;
Precio/m2 38% de la variabilidad
Espacio Sotano 12% de la variabilidad
Espacio Parcela 12% de la varibilidad
Vistas al Mar 9% de la variabilidad
pca
## Standard deviations (1, .., p=14):
## [1] 2.301121e+00 1.324341e+00 1.296212e+00 1.131557e+00 9.117078e-01
## [6] 8.420504e-01 7.606362e-01 7.271734e-01 5.953073e-01 5.291633e-01
## [11] 5.139657e-01 4.851613e-01 4.569679e-01 1.995015e-15
##
## Rotation (n x k) = (14 x 14):
## PC1 PC2 PC3 PC4
## price 0.33517683 0.154019979 -0.130380877 0.13587516
## bedrooms 0.25082558 0.009642013 -0.127738246 -0.39023626
## bathrooms 0.35718859 -0.109033837 -0.059424989 -0.10722165
## sqft_living 0.41079472 0.049334303 -0.040063382 -0.13871432
## sqft_lot 0.09068873 0.257458404 0.639159417 -0.03284621
## floors 0.21293832 -0.451932617 0.061704827 0.21896762
## waterfront 0.07590398 0.285221691 -0.119420237 0.61869750
## view 0.15850037 0.376879363 -0.144909641 0.44366512
## condition -0.05255664 0.372152179 -0.139888084 -0.25968947
## grade 0.37377802 -0.101008543 -0.008101574 0.04954701
## sqft_above 0.38462059 -0.192783898 0.102113121 0.01387785
## sqft_basement 0.13278513 0.462814055 -0.274037482 -0.31364827
## sqft_living15 0.35624929 0.003994464 0.018225629 -0.01681900
## sqft_lot15 0.09489691 0.260512632 0.639112670 -0.03346927
## PC5 PC6 PC7 PC8
## price -0.13588796 0.255852468 -0.023199258 0.252226907
## bedrooms 0.08701449 -0.632199363 -0.239705904 -0.370670794
## bathrooms 0.07762168 -0.204253832 0.318464793 0.154141855
## sqft_living 0.03942413 0.025356388 -0.064757670 0.063128273
## sqft_lot 0.03068809 -0.080810764 0.105911289 0.031158186
## floors -0.15949747 -0.251338341 0.577556842 0.066508072
## waterfront -0.03959279 -0.484003938 -0.316930280 0.375182390
## view 0.09512551 0.088856218 0.317392015 -0.695271895
## condition -0.84825250 -0.059457244 0.160095885 0.001942176
## grade -0.05746863 0.277738988 0.002937423 0.112144259
## sqft_above -0.17869543 0.005170462 -0.230550706 -0.094414630
## sqft_basement 0.41591556 0.042921475 0.296805377 0.307479074
## sqft_living15 -0.03526488 0.307893956 -0.349905605 -0.158352672
## sqft_lot15 0.01973666 -0.057467735 0.033129745 0.023826259
## PC9 PC10 PC11 PC12
## price -0.695288930 0.18486470 -0.09238738 0.09593847
## bedrooms -0.263383016 0.14746678 0.14221447 -0.21486851
## bathrooms 0.270675499 -0.37405856 -0.53239762 -0.11118415
## sqft_living 0.038818489 -0.04102106 -0.06624920 0.36329693
## sqft_lot -0.216057811 -0.55629386 0.36907869 0.02710731
## floors 0.025705579 0.29159257 0.40488773 0.14959583
## waterfront 0.172102153 -0.03079989 0.06518472 -0.04511375
## view -0.006759138 -0.04336973 -0.09243902 -0.00347489
## condition 0.140709520 -0.02959121 0.02800132 -0.02721095
## grade 0.003980220 -0.03316234 0.11420752 -0.79064880
## sqft_above -0.025362993 -0.11368978 -0.20005097 0.34382847
## sqft_basement 0.127937829 0.12751355 0.23667939 0.11055189
## sqft_living15 0.484878544 0.08197957 0.38853079 0.10503486
## sqft_lot15 0.153265832 0.60603325 -0.33111195 -0.08821397
## PC13 PC14
## price 0.380853241 -6.819828e-16
## bedrooms 0.093692842 7.218699e-16
## bathrooms 0.404452297 -1.513049e-15
## sqft_living -0.411233332 -6.992246e-01
## sqft_lot 0.055939218 3.192323e-17
## floors 0.007365561 3.538236e-16
## waterfront -0.044195848 1.078180e-16
## view -0.058595002 4.441069e-17
## condition -0.028844654 -1.802615e-17
## grade -0.339493315 6.337472e-16
## sqft_above -0.375529076 6.304173e-01
## sqft_basement -0.150695358 3.371334e-01
## sqft_living15 0.474433648 4.430968e-17
## sqft_lot15 0.001289053 4.285938e-17
Visualizaremos nuestros 3 Clústeres dentro del plano PC1 y PC2, Observamos que tenemos problemas los valores extremos por un lado y por otro la gran partes de los items se nos acumulan muy próximos lo cual no nos facilita la comprensión de los Grupos.
Planteamos nuesvas alternativas al entender que el PCA es insuficiente para interpretar nuestros Clusters
#join pca data y df cluster
pam_fit$clustering <- as.character(pam_fit$clustering)
pca_data <- data.frame(pca$x, cluster=pam_fit$clustering)
ggplot(pca_data, aes(x=PC1, y=PC2, color=cluster)) + geom_point()
Algoritmo de reducción de dimensionalidad no lineal, encuentra patrones en los datos mediante la identificación de grupos observados basados en la similitud de puntos de datos con múltiples características.
Esta técnica permite utilizar la métrica anteiormente creada, la Distancia de Gower, en nuestro caso se muestran los tres grupos que seleccionamos anteriorenteme con el algortimo PAM.
Asigna los datos multidimensionales creados en la Distancia de Gower anteriormente calculada a un espacio dimensional menor.
Muy útil para el “crowding problem” que implica “la maldición de la dimensión” y básicamente en nuestro caso afecta ya que al aumentar el número de dimensiones la distancia al vecino más próximo aumenta.
Comienza convirtiendo la distancia, nuestro caso Gower, entre los puntos de datos en medidas de probabilidad condicionales que representan similtud entre los datos. Función Gaussiana, probabilidad alta y probabilidad Baja Hay que prestar atención a las colas que son estrechas y pueden acumular mucha relación de puntos.
Representando la distribución de Probabilidad. La idea intuitiva es realizar asignaciones de baja dimensión que representen distribuciones de probabilidad similares, aquí nos podemos encontrar con “crowding problem” debido a las “colas cortas” de las distribuciones Gaussianas. Para subsanar este problema y que los puntos tengan una “cola más larga” la t-sne usa uns distribución T-stundent con un grado de libertad. La optimización de esta distribución t-student se realiza mediante una función Gradiente Descendiente que intuitivamenete representa la fuerza y la atracción-repulsión entre dos puntos. Gradiente positivo implica atracción y al contrario. Este “push-and-pull” hace que los puntos se asienten en espacio de baja dimensionalidad.
Las t-snes no tienen parámetros y optimizan directamente a través de la función de Coste Gradiente que es No Convexa y puede darnos problemas con los mínimos locales. Existen funciones para corregir este crecimiento de la función Gradiente sobre todo al comienzo del algoritmo. Importante el concepto de vecino estocásticos lo cual implica que no está cerrada la frontera de los puntos que son vecinos contra los puntos que no lo son permitiendo al algotimo tener en cuenta la estructura local como la global.( esto lo realizaremos con el parámetro perplexity)
En la siguiente visualización aparecen los 3 clúster dentro los ejes X e Y El número de dimensiones por defecto es 2
Perplexity es el parámetro que usamos para equilibrar el aspecto local y global de los datos, es en cierta medida determinar de forma supuesta cuanto es el número de vecinos quye tendría cada item ( en nuestro ejemplo casa) por defecto es 20, si lo concentramos mucho o lo dispersamos mucho
set.seed=737
tsne_obj <- Rtsne(gower_dist,perplexity = 50, is_distance = TRUE)
tsne_data <- tsne_obj$Y %>%
data.frame() %>%
setNames(c("X", "Y")) %>%
mutate(cluster = factor(pam_fit$clustering))
ggplot(aes(x = X, y = Y), data = tsne_data) +
geom_point(aes(color = cluster))
#join tsne data y df original
df_join<-cbind(tsne_data,df_mas)
plot_ly(
df_join, x = ~X, y = ~Y,
color = ~yr_built, size = ~sqft_living)
## No trace type specified:
## Based on info supplied, a 'scatter' trace seems appropriate.
## Read more about this trace type -> https://plot.ly/r/reference/#scatter
## No scatter mode specifed:
## Setting the mode to markers
## Read more about this attribute -> https://plot.ly/r/reference/#scatter-mode
## Warning: `line.width` does not currently support multiple values.
plot_ly(
df_join, x = ~X, y = ~Y,
color = ~price, size = ~sqft_living)
## No trace type specified:
## Based on info supplied, a 'scatter' trace seems appropriate.
## Read more about this trace type -> https://plot.ly/r/reference/#scatter
## No scatter mode specifed:
## Setting the mode to markers
## Read more about this attribute -> https://plot.ly/r/reference/#scatter-mode
## Warning: `line.width` does not currently support multiple values.
set.seed(767)
tsne_obj <- Rtsne(gower_dist,perplexity = 80, is_distance = TRUE)
tsne_data <- tsne_obj$Y %>%
data.frame() %>%
setNames(c("X", "Y")) %>%
mutate(cluster = factor(pam_fit$clustering))
set.seed(767)
ggplot(aes(x = X, y = Y), data = tsne_data) +
geom_point(aes(color = cluster))
#join tsne data y df original
set.seed(767)
df_join<-cbind(tsne_data,df_mas)
set.seed(767)
plot_ly(
df_join, x = ~X, y = ~Y,
color = ~yr_built, size = ~sqft_living)
## No trace type specified:
## Based on info supplied, a 'scatter' trace seems appropriate.
## Read more about this trace type -> https://plot.ly/r/reference/#scatter
## No scatter mode specifed:
## Setting the mode to markers
## Read more about this attribute -> https://plot.ly/r/reference/#scatter-mode
## Warning: `line.width` does not currently support multiple values.
El objeto tsne_obj$Y contiene las coordenadas X-Y para cada caso de entrada.
Agrupaciones de Clusters anidados de forma Aglomerativa, cada observación comienza en su propio grupo, y los pares de grupos se van fusionando a medida que uno se mueve hacia arriba en la jerarquía. El link Criteria que emplearemos será el de Ward que minimizala suma de diferencias entre los Clusters. Probamos con 7 clúster a partir del dendograma y analizamos los resultados.
set.seed(767)
cluster_hierarchical=hclust(dist(tsne_obj$Y), method = "ward.D")
plot(cluster_hierarchical, cex = 0.6, hang = -1)
set.seed(767)
df_join$hclust = factor(cutree(cluster_hierarchical, 9))
set.seed(767)
prueba <- subset( df_join, select = -cluster )
ggplot(aes(x = X, y = Y), data = prueba) +
geom_point(aes(color = hclust))
#write.csv(prueba,file="cluster.csv")